package com.zdxk.msgPush.websocket.annotion;

import com.zdxk.msgPush.common.config.ServiceConfig;
import com.zdxk.msgPush.websocket.annotion.enums.RequestMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

public class RequestMappingProcessor {

    private static Logger logger = LoggerFactory.getLogger(RequestMappingProcessor.class);

    //存放url到RequestHandler的映射
    public static HashMap<String, RequestHandler> requestMappingMap = new HashMap<>();

    public static List<String> getAllFilePath(String rootPath) throws IOException {
        List<String> dirList = new ArrayList<>();
        dirList.add(rootPath);
        List<String> allfileList = new ArrayList<>();
        int index = 0;
        while (index < dirList.size()){
            Enumeration<URL> enumeration = RequestMappingProcessor.class.getClassLoader().getResources(dirList.get(index++));
            while (enumeration.hasMoreElements()){
                URL url = enumeration.nextElement();
                File file = new File(url.getFile());
                File[] fileList = file.listFiles();
                for(File tempFile : fileList){
                    String temp = tempFile.getPath().replace("\\","/");
                    String packname = temp.substring(temp.indexOf(rootPath));
                    if(tempFile.isFile()){
                        allfileList.add(packname.replaceAll("/",".").replace(".class",""));
                    }else {
                        dirList.add(packname);
                    }
                }
            }
        }
        return allfileList;
    }


    /**
     * 扫描解析指定包下的@Controller和@RequestMapping注解
     * <p>
     * 只能扫描class文件，暂未实现扫描jar包
     *
     * @return 生成的映射表
     */
    public static HashMap<String, RequestHandler> scanRequestMapping() throws IOException {
        //扫描的包路径
        String pkgPath = ServiceConfig.getConf("websocket.controllerPackage");
        requestMappingMap.clear();
        List<String> fileList = getAllFilePath(pkgPath);
        try {
            for (String path : fileList) {
                Class clazz = Thread.currentThread().getContextClassLoader().loadClass(path);
                WebsocketController controller = (WebsocketController) clazz.getAnnotation(WebsocketController.class);
                if (controller != null) {
                    System.out.println(clazz.getName());
                    WebsocketRequestMapping parentRequestMapping = (WebsocketRequestMapping) clazz.getAnnotation(WebsocketRequestMapping.class);
                    //类注解上的一级路径
                    String basePath = null;
                    RequestMethod baseMethod = null;
                    if (parentRequestMapping != null) {
                        //获取类注解上的一级路径
                        basePath = ensurePath(parentRequestMapping.value());
                        baseMethod = parentRequestMapping.method();
                        //忽略类注解上的auth
                        //baseAuth = parentRequestMapping.auth();

                        //默认为RequestMethod.GET
                        if (baseMethod == RequestMethod.DEFAULT) baseMethod = RequestMethod.GET;
                    }
                    //生成类的实例对象
                    Object instance = clazz.newInstance();
                    System.out.println("扫描到类 " + instance.getClass().getCanonicalName());
                    for (Method method : clazz.getDeclaredMethods()) {
                        System.out.println("    " + method.getName() + "()");
                        WebsocketRequestMapping requestMapping = method.getAnnotation(WebsocketRequestMapping.class);
                        if (requestMapping != null) {//获取到方法上的注解
                            method.setAccessible(true);
                            //生成RequestHandler实例
                            RequestHandler warp = new RequestHandler();
                            //拼接生成最终的url
                            warp.path = basePath + ensurePath(requestMapping.value());
                            //获取方法注解上的RequestMethod
                            RequestMethod requestMethod = requestMapping.method();
                            if (requestMethod == RequestMethod.DEFAULT) {
                                //如果类注解设置了RequestMethod，而方法注解没有设置RequestMethod，则类注解会覆盖方法注解的请求方法
                                warp.requestMethod = baseMethod != null ? baseMethod : RequestMethod.GET;//默认为GET
                            } else {//否则使用方法注解上的RequestMethod
                                warp.requestMethod = requestMethod;
                            }
                            warp.method = method;
                            //默认为true
                            warp.isAuth = requestMapping.auth();
                            warp.clazz = clazz;
                            warp.instance = instance;
                            //检查参数，这里还可以再检查一下返回值类型什么的
                            //这里的方法参数类型和个数都是定死了，可以拓展支持不同参数类型和返回类型
                            requestMappingMap.put(warp.path, warp);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (requestMappingMap != null) {
            System.out.println("url映射：");
            for (Map.Entry<String, RequestHandler> entry : requestMappingMap.entrySet()) {
                RequestHandler warp = entry.getValue();
                System.out.println(warp.path + "  " + warp.requestMethod + "  " + warp.clazz.getCanonicalName() + "." + warp.method.getName() + "()");
            }
        }
        return requestMappingMap;
    }


    /**
     * 规范url格式
     * <p>
     * 标准格式为前有ur开头l“/”而后面没有 如 /user、/user/login等
     */
    private static String ensurePath(String path) {
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        return path;
    }

    public static HashMap<String, RequestHandler> getRequestMappingMap() {
        return requestMappingMap;
    }
}
